﻿namespace EyeOpen.Log4NetExtensions
{
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.IO;
    using System.Linq;
    using EyeOpen.Log4NetExtensions.Appenders;
    using log4net.Appender;
    using log4net.Core;
    using log4net.Layout;

    [Serializable]
    public abstract class Log4NetFluentConfigurator
    {
        protected static readonly PatternLayout PatternLayout = new PatternLayout("%date [%thread] %-5level %logger %ndc - %message%newline");
        protected static readonly XmlLayout XmlLayout = new XmlLayout();
        protected static readonly ExceptionLayout ExceptionLayout = new ExceptionLayout();
        protected static readonly string LogDirectory = ConfigurationManager.AppSettings["LogDirectory"];

        protected static readonly string SqlServerProvider = "System.Data.SqlClient";

        /// <summary>
        /// Configures this instance using FluentInterface.
        /// </summary>
        public void Configure()
        {
            CreateAppenderList()
                .ToList()
                .ForEach(AddAppender);
        }

        protected DbAdoNetAppender CreateAdoNetAppender(string connectionKey, Level threshold)
        {
            var connectionStringSettings = ReadConnectionFromConfigurationFile(connectionKey);

            if (connectionStringSettings.ProviderName == "System.Data.SqlClient")
            {
                var adoNetAppender = 
                    new SqlAdoNetAppender
                         {
                             ConnectionString = connectionStringSettings.ConnectionString,
                             Threshold = threshold
                         };

                return adoNetAppender;
            }

            var message = string.Format("Provider \"{0}\" is not supported.", connectionStringSettings.ProviderName);
            throw new ConfigurationErrorsException(message);
        }

        protected abstract IEnumerable<IAppender> CreateAppenderList();

        protected string ReadKeyFromConfigurationFile(string key)
        {
            var value = ConfigurationManager.AppSettings[key];

            if (value == null)
            {
                var message = string.Format("Cannot find the key \"{0}\" in the configuration file.", key);
                throw new ConfigurationErrorsException(message);
            }
            
            if (string.IsNullOrEmpty(value.Trim()))
            {
                var message = string.Format("The value for key \"{0}\" in the configuration file cannot be spaces or empty.", key);
                throw new ConfigurationErrorsException(message);
            }

            return value;
        }

        protected ConnectionStringSettings ReadConnectionFromConfigurationFile(string connectionKey)
        {
            var value = ConfigurationManager.ConnectionStrings[connectionKey];

            if (value == null)
            {
                var message = string.Format("Cannot find the connection key \"{0}\" in the configuration file.", connectionKey);
                throw new ConfigurationErrorsException(message);
            }

            return value;
        }

        private void AddAppender(IAppender appender)
        {
            var appenderSkeleton = appender as IOptionHandler;

            if (appenderSkeleton != null)
            {
                appenderSkeleton.ActivateOptions();
            }

            log4net
                .Config
                .BasicConfigurator
                .Configure(appender);
        }
    }
}